package com.android.yinghebike.ui.fragment

import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Color
import android.location.Location
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageView
import android.widget.RelativeLayout
import androidx.activity.OnBackPressedCallback
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.android.baselibrary.util.Util
import com.android.yinghebike.R
import com.android.yinghebike.manager.MapMarkersManager
import com.android.yinghebike.ui.activity.MapboxNavigationActivity
import com.android.yinghebike.ui.view.Nav_SearchPlace_View
import com.mapbox.android.core.location.LocationEngine
import com.mapbox.android.core.location.LocationEngineProvider
import com.mapbox.android.gestures.Utils
import com.mapbox.api.directions.v5.DirectionsCriteria
import com.mapbox.api.directions.v5.models.DirectionsRoute
import com.mapbox.api.directions.v5.models.RouteOptions
import com.mapbox.geojson.Point
import com.mapbox.maps.BuildConfig
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.MapView
import com.mapbox.maps.Style
import com.mapbox.maps.extension.style.layers.properties.generated.Visibility
import com.mapbox.maps.plugin.Plugin
import com.mapbox.maps.plugin.attribution.AttributionPlugin
import com.mapbox.maps.plugin.gestures.OnMapClickListener
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.maps.plugin.locationcomponent.OnIndicatorPositionChangedListener
import com.mapbox.maps.plugin.locationcomponent.location
import com.mapbox.maps.plugin.logo.LogoPlugin
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
import com.mapbox.navigation.base.options.EventsAppMetadata
import com.mapbox.navigation.base.options.NavigationOptions
import com.mapbox.navigation.base.route.RouterCallback
import com.mapbox.navigation.base.route.RouterFailure
import com.mapbox.navigation.base.route.RouterOrigin
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.MapboxNavigationProvider
import com.mapbox.navigation.core.directions.session.RoutesObserver
import com.mapbox.navigation.core.trip.session.LocationMatcherResult
import com.mapbox.navigation.core.trip.session.LocationObserver
import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions
import com.mapbox.navigation.ui.maps.route.line.model.RouteLine
import com.mapbox.navigation.ui.maps.route.line.model.RouteLineColorResources
import com.mapbox.navigation.ui.maps.route.line.model.RouteLineResources
import com.mapbox.search.*
import com.mapbox.search.offline.OfflineResponseInfo
import com.mapbox.search.offline.OfflineSearchEngine
import com.mapbox.search.offline.OfflineSearchEngineSettings
import com.mapbox.search.offline.OfflineSearchResult
import com.mapbox.search.record.HistoryRecord
import com.mapbox.search.result.SearchResult
import com.mapbox.search.result.SearchSuggestion
import com.mapbox.search.ui_custom.adapter.engines.SearchEngineUiAdapter
import com.mapbox.search.ui_custom.view.*
import com.mapbox.search.ui_custom.view.place.SearchPlace


class NavFragment1 : Fragment() {

    private lateinit var locationEngine: LocationEngine

    private lateinit var searchResultsView: SearchResultsView
    private lateinit var searchEngineUiAdapter: SearchEngineUiAdapter
    lateinit var searchEngine: SearchEngine

    private lateinit var mapView: MapView
    private lateinit var mapMarkersManager: MapMarkersManager

    private lateinit var queryEditText: EditText
    private lateinit var nav_SearchPlaceView: Nav_SearchPlace_View
    private lateinit var iv_deleteinput: ImageView
    private lateinit var rl_search_result: RelativeLayout
    private lateinit var iv_input_back: ImageView


    var lastLocation: Point? = null  //最新位置

    private val onBackPressedCallback = object : OnBackPressedCallback(false) {
        override fun handleOnBackPressed() {
            when {
                mapMarkersManager.hasMarkers -> {
                    mapMarkersManager.clearMarkers()
                }
                else -> {
                    if (BuildConfig.DEBUG) {
                        error("This OnBackPressedCallback should not be enabled")
                    }
                    Log.i("SearchApiExample", "This OnBackPressedCallback should not be enabled")
                    isEnabled = false
//                    onBackPressedDispatcher.onBackPressed()
                }
            }
        }
    }
    lateinit var mapboxNavigation: MapboxNavigation

    // RouteLine: Route line related colors can be customized via the RouteLineColorResources.
    private val routeLineColorResources by lazy {
        RouteLineColorResources.Builder()
            .routeLineTraveledColor(Color.LTGRAY)
            .routeLineTraveledCasingColor(Color.GRAY)
            .build()
    }

    private val options: MapboxRouteLineOptions by lazy {
        MapboxRouteLineOptions.Builder(context!!)
            .withRouteLineResources(routeLineResources)
            .withRouteLineBelowLayerId("road-label-navigation")
            .withVanishingRouteLineEnabled(true)
            .displaySoftGradientForTraffic(false)
            .build()
    }

    private val routeLineApi: MapboxRouteLineApi by lazy {
        MapboxRouteLineApi(options)
    }

    private val routeLineView by lazy {
        MapboxRouteLineView(options)
    }

    private val routeLineResources: RouteLineResources by lazy {
        RouteLineResources.Builder()
            .routeLineColorResources(routeLineColorResources)
            .build()
    }
    private val navigationLocationProvider by lazy {
        NavigationLocationProvider()
    }

    private lateinit var rootView: View

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        rootView = inflater.inflate(R.layout.fragment_nav1, container, false)
        return rootView;
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

//        onBackPressedDispatcher.addCallback(onBackPressedCallback)
        val appContext = context?.applicationContext ?: return
        locationEngine = LocationEngineProvider.getBestLocationEngine(appContext)

        rl_search_result = rootView.findViewById(R.id.rl_search_result)
        mapView = rootView.findViewById(R.id.map_view)
        mapView.getMapboxMap().also { mapboxMap ->
            mapboxMap.loadStyleUri(getMapStyleUri())

            mapView.location.updateSettings {
                enabled = true
                pulsingEnabled = true
            }

            mapView.location.addOnIndicatorPositionChangedListener(object :
                OnIndicatorPositionChangedListener {
                override fun onIndicatorPositionChanged(point: Point) {
                    if (lastLocation == null) {
                        mapView.getMapboxMap().setCamera(
                            CameraOptions.Builder()
                                .center(point)
                                .zoom(14.0)
                                .build()
                        )
                    }
                    lastLocation = point
//                    mapView.location.removeOnIndicatorPositionChangedListener(this)
                }
            })
        }
        //地图长按，显示点信息
        mapView.gestures.addOnMapLongClickListener { point ->
            showPlace(point)
            true
        }
        //地图点击，选择路线
        mapView.gestures.addOnMapClickListener(mapClickListener)

        //地点控件
        nav_SearchPlaceView = rootView.findViewById(R.id.nav_SearchResultView)
        nav_SearchPlaceView.setBtnClick(object : Nav_SearchPlace_View.OnBtnClick {

            override fun navClick(point: Point?) {
                //点击搜索路线
                findRoute(point);
            }

            override fun startClick(point: Point?) {
                //点击开始导航
                if (point != null) {
                    goToNav(point)
                }
            }

            override fun closeClick() {
                //关闭地点信息
                hidePlace()
            }

            override fun selectRouter(router: DirectionsRoute) {
                //切换路线
                reOrderedRoute(router)
            }
        })
        //搜索框
        iv_input_back = rootView.findViewById(R.id.iv_input_back)
        queryEditText = rootView.findViewById(R.id.query_text)
        queryEditText.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus ->
            if (hasFocus) {
                rl_search_result.visibility = View.VISIBLE
                iv_input_back.visibility = View.VISIBLE
            } else {
                rl_search_result.visibility = View.GONE
                iv_input_back.visibility = View.GONE
            }
        }
        iv_input_back.setOnClickListener {
            Log.i("test", "点击")
            closeSearchView()
        }

        queryEditText.addTextChangedListener(object : TextWatcher {

            override fun onTextChanged(text: CharSequence, start: Int, before: Int, count: Int) {
                searchEngineUiAdapter.search(text.toString())
                rl_search_result.visibility = View.VISIBLE
                displayClearImg()
            }

            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
                // Nothing to do
            }

            override fun afterTextChanged(s: Editable) {
                // Nothing to do
            }
        })

        //标记管理类
        mapMarkersManager = MapMarkersManager(mapView)
        mapMarkersManager.onMarkersChangeListener = {
            updateOnBackPressedCallbackEnabled()
        }
        //搜索相关
        searchResultsView =
            rootView.findViewById<SearchResultsView>(R.id.search_results_view).apply {
                initialize(
                    SearchResultsView.Configuration(CommonSearchViewConfiguration(DistanceUnitType.IMPERIAL))
                )
//                visibility = View.GONE
            }

        searchEngine = SearchEngine.createSearchEngineWithBuiltInDataProviders(
            apiType = ApiType.GEOCODING,
            settings = SearchEngineSettings(getString(R.string.mapbox_access_token))
        )

        val offlineSearchEngine = OfflineSearchEngine.create(
            OfflineSearchEngineSettings(getString(R.string.mapbox_access_token))
        )

        searchEngineUiAdapter = SearchEngineUiAdapter(
            view = searchResultsView,
            searchEngine = searchEngine,
            offlineSearchEngine = offlineSearchEngine,
        )

        searchEngineUiAdapter.searchMode = SearchMode.AUTO
        searchEngineUiAdapter.addSearchListener(object : SearchEngineUiAdapter.SearchListener {

            override fun onSuggestionsShown(
                suggestions: List<SearchSuggestion>,
                responseInfo: ResponseInfo
            ) {
                // Nothing to do
            }

            override fun onCategoryResultsShown(
                suggestion: SearchSuggestion,
                results: List<SearchResult>,
                responseInfo: ResponseInfo
            ) {
//                mapMarkersManager.showMarkers(results.map { it.coordinate })
            }

            override fun onOfflineSearchResultsShown(
                results: List<OfflineSearchResult>,
                responseInfo: OfflineResponseInfo
            ) {
                // Nothing to do
            }

            override fun onSuggestionSelected(searchSuggestion: SearchSuggestion): Boolean {
                return false
            }

            override fun onSearchResultSelected(
                searchResult: SearchResult,
                responseInfo: ResponseInfo
            ) {
                Log.i("test", "onSearchResultSelected")
                queryEditText.setText("")
                showPlace(SearchPlace.createFromSearchResult(searchResult, responseInfo))

            }

            override fun onOfflineSearchResultSelected(
                searchResult: OfflineSearchResult,
                responseInfo: OfflineResponseInfo
            ) {
//                mapMarkersManager.showMarker(searchResult.coordinate)
            }

            override fun onError(e: Exception) {
//                Toast.makeText(applicationContext, "Error happened: $e", Toast.LENGTH_SHORT).show()
            }

            override fun onHistoryItemClick(historyRecord: HistoryRecord) {
                showPlace(
                    SearchPlace.createFromIndexableRecord(
                        historyRecord,
                        distanceMeters = null
                    )
                )
            }

            override fun onPopulateQueryClick(
                suggestion: SearchSuggestion,
                responseInfo: ResponseInfo
            ) {
                Log.i("test", "点击导航键")
                searchEngine.select(
                    suggestion,
                    object : SearchSuggestionsCallback, SearchSelectionCallback {

                        override fun onSuggestions(
                            suggestions: List<SearchSuggestion>,
                            responseInfo: ResponseInfo
                        ) {
                        }

                        override fun onResult(
                            suggestion: SearchSuggestion,
                            result: SearchResult,
                            responseInfo: ResponseInfo
                        ) {
                            closeSearchView()
                            goToNav(result.coordinate)
                        }

                        override fun onCategoryResult(
                            suggestion: SearchSuggestion,
                            results: List<SearchResult>,
                            responseInfo: ResponseInfo
                        ) {
                        }

                        override fun onError(e: Exception) {
                        }
                    })
            }

            override fun onFeedbackItemClick(responseInfo: ResponseInfo) {
                // Not implemented
            }
        })

        //清除文本
        iv_deleteinput = rootView.findViewById(R.id.iv_deleteinput)
        iv_deleteinput.setOnClickListener(object : View.OnClickListener {
            override fun onClick(p0: View?) {
                queryEditText.setText("")
                Log.i("test", "点击")
            }
        })

        //点背景关闭搜索结果
        rl_search_result.setOnClickListener(object : View.OnClickListener {
            override fun onClick(p0: View?) {
                closeSearchView()
            }
        })

        //隐藏地图logo和问号
        val logoPlugin: LogoPlugin? = mapView.getPlugin(Plugin.MAPBOX_LOGO_PLUGIN_ID)
        if (logoPlugin != null) {
            logoPlugin.enabled = false
        }
        val attributionPlugin: AttributionPlugin? =
            mapView.getPlugin(Plugin.MAPBOX_ATTRIBUTION_PLUGIN_ID)
        if (attributionPlugin != null) {
            attributionPlugin.enabled = false
        }

    }

    //显示清除按钮
    fun displayClearImg() {
        if (TextUtils.isEmpty(queryEditText.text)) {
            iv_deleteinput.visibility = View.GONE
        } else {
            iv_deleteinput.visibility = View.VISIBLE
        }
    }

    //初始化导航对象
    private fun initNavigation() {
        mapboxNavigation = MapboxNavigationProvider.create(
            NavigationOptions.Builder(context!!)
                .accessToken(getString(R.string.mapbox_access_token))
                .eventsAppMetadata(
                    EventsAppMetadata.Builder(
                        com.android.yinghebike.BuildConfig.APPLICATION_ID,
                        com.android.yinghebike.BuildConfig.VERSION_NAME
                    ).build()
                ).build()
        )
        mapboxNavigation.registerLocationObserver(locationObserver)
        mapboxNavigation.registerRoutesObserver(routesObserver)

    }

    private fun destroyNavigation() {
        mapboxNavigation.unregisterLocationObserver(locationObserver)
        mapboxNavigation.unregisterRoutesObserver(routesObserver)
        mapboxNavigation.onDestroy()
    }

    override fun onResume() {
        super.onResume()
        if (context != null) {
//            if (!this::mapboxNavigation.isInitialized || mapboxNavigation.isDestroyed) {
//                initNavigation();
//            }
            initNavigation()
        }
    }

    private val locationObserver = object : LocationObserver {
        override fun onNewRawLocation(rawLocation: Location) {}
        override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {

            navigationLocationProvider.changePosition(
                locationMatcherResult.enhancedLocation,
                locationMatcherResult.keyPoints,
            )
        }
    }

    private val routesObserver: RoutesObserver = RoutesObserver { result ->
        val routeLines = result.routes.map { RouteLine(it, null) }
        routeLineApi.setRoutes(
            routeLines
        ) { value ->
            mapView.getMapboxMap().getStyle()?.apply {
                routeLineView.renderRouteDrawData(this, value)
            }
        }
    }

    fun findRoute(destination: Point?) {
        val origin = lastLocation

        val routeOptions = RouteOptions.builder()
            .applyDefaultNavigationOptions(DirectionsCriteria.PROFILE_CYCLING)
//            .applyLanguageAndVoiceUnitOptions(context!!)
            .coordinatesList(listOf(origin, destination))
//            .layersList(listOf(mapboxNavigation.getZLevel(), null))
            .alternatives(true)
            .build()
        mapboxNavigation.requestRoutes(
            routeOptions,
            routesReqCallback
        )
    }

    //获取路线
    private val routesReqCallback: RouterCallback = object : RouterCallback {
        override fun onRoutesReady(routes: List<DirectionsRoute>, routerOrigin: RouterOrigin) {
            mapboxNavigation.setRoutes(routes)
//            if (routes.isNotEmpty()) {
//                nav_SearchPlaceView.setRouter(routes.first())
//                Log.i("test", "获取到路线：" + routes.size)
//            }
            nav_SearchPlaceView.setRouter(routes)
        }

        override fun onCanceled(routeOptions: RouteOptions, routerOrigin: RouterOrigin) {
            Log.i("test", "获取路线 onCanceled")
        }

        override fun onFailure(reasons: List<RouterFailure>, routeOptions: RouteOptions) {
            Log.i("test", "获取路线失败：" + reasons[0].message)
        }
    }

    private val mapClickListener = OnMapClickListener { point ->
        mapView.getMapboxMap().getStyle()?.apply {
            // Since this listener is reacting to all map touches, if the primary and alternative
            // routes aren't visible it's assumed the touch isn't related to selecting an
            // alternative route.
            val primaryLineVisibility = routeLineView.getPrimaryRouteVisibility(this)
            val alternativeRouteLinesVisibility = routeLineView.getAlternativeRoutesVisibility(this)
            if (
                primaryLineVisibility == Visibility.VISIBLE &&
                alternativeRouteLinesVisibility == Visibility.VISIBLE
            ) {
                routeLineApi.findClosestRoute(
                    point,
                    mapView.getMapboxMap(),
                    Utils.dpToPx(30f)
                ) { result ->
                    result.onValue { value ->
                        if (value.route != routeLineApi.getPrimaryRoute()) {
                            val reOrderedRoutes = routeLineApi.getRoutes()
                                .filter { it != value.route }
                                .toMutableList()
                                .also {
                                    it.add(0, value.route)
                                }
                            mapboxNavigation.setRoutes(reOrderedRoutes)
                        }
                        nav_SearchPlaceView.setRouter(value.route)
                    }
                }
            }
        }

        false
    }

    //选择了路线，就重新排序路线
    fun reOrderedRoute(route: DirectionsRoute)
    {
        if (route != routeLineApi.getPrimaryRoute()) {
            val reOrderedRoutes = routeLineApi.getRoutes()
                .filter { it != route }
                .toMutableList()
                .also {
                    it.add(0, route)
                }
            mapboxNavigation.setRoutes(reOrderedRoutes)
        }
        nav_SearchPlaceView.setRouter(route)
    }

    //去导航界面
    fun goToNav(point: Point) {
        destroyNavigation()

        var intent = Intent()
        intent.setClass(context!!, MapboxNavigationActivity::class.java)
        val route = mapboxNavigation.getRoutes().firstOrNull()
        if (route != null) {
            intent.putExtra("route", route)
        } else {
            intent.putExtra("destination", point)
        }
        startActivity(intent)

//        hidePlace()
    }

    //显示地点信息
    fun showPlace(point: Point) {
        nav_SearchPlaceView.setSearchPoint(point)
        nav_SearchPlaceView.visibility = View.VISIBLE
        mapMarkersManager.showMarker(point, false)
        //清除路线
        clearRouter();
    }

    //显示地点信息
    fun showPlace(searchPlace: SearchPlace) {
        closeSearchView()
        nav_SearchPlaceView.setSearchPlace(searchPlace)
        nav_SearchPlaceView.visibility = View.VISIBLE
        mapMarkersManager.showMarker(searchPlace.coordinate, true)

        clearRouter();
    }

    //隐藏地点信息
    fun hidePlace() {
        iv_input_back.visibility = View.GONE
        nav_SearchPlaceView.visibility = View.GONE
        mapMarkersManager.clearMarkers()
        clearRouter();
    }

    //清除路线
    fun clearRouter() {
        nav_SearchPlaceView.setRouter(null)
        mapboxNavigation.setRoutes(emptyList())
    }

    fun isPermissionGranted(permission: String): Boolean {
        return context?.let {
            ContextCompat.checkSelfPermission(
                it,
                permission
            )
        } == PackageManager.PERMISSION_GRANTED
    }

    private fun updateOnBackPressedCallbackEnabled() {
        onBackPressedCallback.isEnabled = mapMarkersManager.hasMarkers
    }

    //关闭搜索框
    private fun closeSearchView() {
        queryEditText.clearFocus()
        Util.showKeyBoard(false, context, queryEditText)
//        queryEditText.hideKeyboard()
//        rl_search_result.visibility = View.GONE
    }


    private fun getMapStyleUri(): String {
        return when (val darkMode =
            resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
            Configuration.UI_MODE_NIGHT_YES -> Style.DARK
            Configuration.UI_MODE_NIGHT_NO,
            Configuration.UI_MODE_NIGHT_UNDEFINED -> Style.MAPBOX_STREETS
            else -> error("Unknown mode: $darkMode")
        }
    }


}